﻿using System;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Elasticsearch.Net;
using NewLife;

namespace EMC.VISITOR.Core
{
    public class HttpUtil
    {
        /// <summary>
        /// 设置信息参数
        /// </summary>
        /// <param name="appkey">合作方APPKey</param>
        /// <param name="secret">合作方APPSecret</param>
        /// <param name="ip">平台IP</param>
        /// <param name="port">平台端口，默认HTTPS的443端口</param>
        /// <param name="isHttps">是否启用HTTPS协议，默认HTTPS</param>
        /// <return></return>
        public static void SetPlatformInfo(string appkey, string secret, string ip, int port = 443, bool isHttps = true)
        {
            _appkey = appkey;
            _secret = secret;
            _ip = ip;
            _port = port;
            _isHttps = isHttps;

            // 设置并发数，如不设置默认为2
            ServicePointManager.DefaultConnectionLimit = 512;
        }
        public static string HttpGetBase64String(string imageUrl, string saveCompressImagePath, int quality = 115, double minByteValue = 0.2 * 1024 * 1024)
        {
            try
            {
                ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(remoteCertificateValidate);
                var imageBytes = HttpGet(imageUrl, 10);
                //压缩图片 
                if (imageBytes.Length > minByteValue)
                {
                    imageBytes = CompressImage(imageBytes, quality, 300, null);
                }
                if (!saveCompressImagePath.IsNullOrEmpty())
                    File.WriteAllBytes(saveCompressImagePath, imageBytes);
                return Convert.ToBase64String(imageBytes);

            }
            catch (Exception ex)
            {
                return null;
            }
        }

        /// <summary>
        /// 压缩图片
        /// </summary>
        /// <param name="imageBytes"></param>
        /// <param name="quality">图片质量 >0  <100</param>
        /// <param name="newWidth">压缩后的宽度</param>
        /// <returns></returns>
        /// <exception cref="ArgumentOutOfRangeException"></exception>
        /// <exception cref="NotSupportedException"></exception>
        private static byte[] CompressImage(byte[] imageBytes, long quality, int? newWidth = null, int? newHeight = null)
        {
            // Check if the quality is within the valid range
            //if (quality < 0L || quality > 100L)
            //{
            //    throw new ArgumentOutOfRangeException(nameof(quality), "Quality must be between 0 and 100.");
            //}

            using (var ms = new MemoryStream(imageBytes))
            {
                using (var originalImage = System.Drawing.Image.FromStream(ms))
                {
                    var image = FixOrientation(originalImage);
                    var target = ZoomAuto(image, newWidth, newHeight);
                    // Create a new MemoryStream to hold the compressed image
                    using (var compressedStream = new MemoryStream())
                    {
                        // Get the JPEG encoder
                        var encoder = GetEncoder(ImageFormat.Jpeg);
                        if (encoder == null)
                        {
                            throw new NotSupportedException("JPEG encoder not found.");
                        }

                        // Create an EncoderParameters object with one EncoderParameter object in the array
                        var encoderParameters = new EncoderParameters(1);
                        encoderParameters.Param = new EncoderParameter[] { new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality) };

                        // Save the image to the MemoryStream with the JPEG encoder and the quality parameter
                        target.Save(compressedStream, encoder, encoderParameters);

                        // Return the compressed image as a byte array
                        return compressedStream.ToArray();
                    }
                }
            }
        }
        /// <summary>
        /// 修复图片方向
        /// </summary>
        /// <param name="img"></param>
        /// <returns></returns>
        private static System.Drawing.Image FixOrientation(System.Drawing.Image img)
        {
            // 检查是否存在Exif Orientation属性
            if (Array.IndexOf(img.PropertyIdList, 274) > -1)
            {
                var orientation = (int)img.GetPropertyItem(274).Value[0];
                switch (orientation)
                {
                    case 1:
                        // 正常方向，无需旋转
                        break;
                    case 3:
                        // 旋转180度
                        img.RotateFlip(RotateFlipType.Rotate180FlipNone);
                        break;
                    case 6:
                        // 顺时针旋转90度
                        img.RotateFlip(RotateFlipType.Rotate90FlipNone);
                        break;
                    case 8:
                        // 逆时针旋转90度
                        img.RotateFlip(RotateFlipType.Rotate270FlipNone);
                        break;
                }

                // 重置Orientation标签为1（正常方向）
                img.RemovePropertyItem(274);
            }

            return img;
        }
        /// <summary>
        /// 图片等比缩放
        /// </summary>
        /// <param name="postedfile">原图httppostedfile对象</param>
        /// <param name="savepath">缩略图存放地址</param>
        /// <param name="targetwidth">指定的最大宽度</param>
        /// <param name="targetheight">指定的最大高度</param>
        /// <param name="watermarktext">水印文字(为""表示不使用水印)</param>
        /// <param name="watermarkimage">水印图片路径(为""表示不使用水印)</param>
        private static Bitmap ZoomAuto(System.Drawing.Image image, int? targetWidth = null, int? targetHeight = null)
        {
            //float ratio = (float)width / (float)image.Width;
            //int newWidth = (int)(image.Width * ratio);
            //int newHeight = (int)(image.Height * ratio);
            //Bitmap bmp = new Bitmap(newWidth, newHeight, PixelFormat.Format24bppRgb);
            //bmp.SetResolution(image.HorizontalResolution, image.VerticalResolution);
            //Graphics graphic = Graphics.FromImage(bmp);
            //graphic.SmoothingMode = SmoothingMode.HighQuality;
            //graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
            //graphic.DrawImage(image, new System.Drawing.Rectangle(0, 0, newWidth, newHeight));
            //graphic.Dispose();
            //return bmp;

            // 计算缩放比例
            float ratio;
            int newWidth, newHeight;

            if (targetWidth != null)
            {
                // 按宽度缩放
                ratio = (float)targetWidth.Value / image.Width;
                newWidth = targetWidth.Value;
                newHeight = (int)(image.Height * ratio);
            }
            else
            {
                // 按高度缩放
                ratio = (float)targetHeight.Value / image.Height;
                newHeight = targetHeight.Value;
                newWidth = (int)(image.Width * ratio);
            }

            // 创建目标位图
            Bitmap resizedBitmap = new Bitmap(newWidth, newHeight, PixelFormat.Format32bppArgb);
            resizedBitmap.SetResolution(image.HorizontalResolution, image.VerticalResolution);

            // 使用Graphics对象进行高质量绘制
            using (Graphics graphic = Graphics.FromImage(resizedBitmap))
            {
                graphic.SmoothingMode = SmoothingMode.HighQuality;
                graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;

                // 绘制缩放后的图片
                graphic.DrawImage(image, new System.Drawing.Rectangle(0, 0, newWidth, newHeight));
            }

            return resizedBitmap;
        }
        /// <summary>
        /// 图片缩放
        /// </summary>
        /// <param name="image"></param>
        /// <param name="newWidth">图片宽</param>
        /// <param name="newHeight">图片高</param>
        /// <returns></returns>
        private static System.Drawing.Image ResizeImage(System.Drawing.Image image, int newWidth, int newHeight)
        {
            Bitmap resizedImage = new Bitmap(newWidth, newHeight);
            using (Graphics graphics = Graphics.FromImage(resizedImage))
            {
                graphics.DrawImage(image, new System.Drawing.Rectangle(0, 0, newWidth, newHeight));
            }
            return resizedImage;
        }
        private static ImageCodecInfo GetEncoder(ImageFormat format)
        {
            var codecs = ImageCodecInfo.GetImageDecoders();
            foreach (var codec in codecs)
            {
                if (codec.FormatID == format.Guid)
                {
                    return codec;
                }
            }
            return null;
        }


        /// <summary>
        /// HTTP GET请求
        /// </summary>
        /// <param name="uri">HTTP接口Url，不带协议和端口，如/artemis/api/resource/v1/cameras/indexCode?cameraIndexCode=a10cafaa777c49a5af92c165c95970e0</param>
        /// <param name="timeout">请求超时时间，单位：秒</param>
        /// <returns></returns>
        public static byte[] HttpGet(string uri, int timeout)
        {
            HttpWebRequest request = null;
            HttpWebResponse response = null;
            Stream responseStream = null;
            MemoryStream memoryStream = null;

            try
            {
                request = (HttpWebRequest)WebRequest.Create(uri);
                request.Method = "GET";
                request.Timeout = timeout*1000; // 10秒超时

                response = (HttpWebResponse)request.GetResponse();
                responseStream = response.GetResponseStream();

                // 将响应流读取到内存流
                memoryStream = new MemoryStream();
                responseStream.CopyTo(memoryStream);

                return memoryStream.ToArray();
            }
            catch (WebException ex)
            {
                if (ex.Response != null)
                {
                    using (var errorResponse = (HttpWebResponse)ex.Response)
                    using (var errorStream = errorResponse.GetResponseStream())
                    using (var reader = new StreamReader(errorStream))
                    {
                        string errorDetails = reader.ReadToEnd();
                        throw new Exception($"HTTP Error: {(int)errorResponse.StatusCode} - {errorDetails}");
                    }
                }
                throw;
            }
            finally
            {
                responseStream?.Dispose();
                response?.Dispose();
                memoryStream?.Dispose();
            }
        }

        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true;
        }
        /// <summary>
        /// HTTP Post请求
        /// </summary>
        /// <param name="url"></param>
        /// <param name="postData"></param>
        /// <param name="contentType"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static byte[] HttpPost(string url, byte[] postData, string contentType = "application/x-www-form-urlencoded")
        {
            HttpWebRequest request = null;
            HttpWebResponse response = null;
            Stream requestStream = null;
            Stream responseStream = null;
            MemoryStream memoryStream = null;

            try
            {
                request = (HttpWebRequest)WebRequest.Create(url);
                request.Method = "POST";
                request.ContentType = contentType;
                request.Timeout = 10000;

                // 写入请求体
                requestStream = request.GetRequestStream();
                requestStream.Write(postData, 0, postData.Length);
                requestStream.Close();

                // 获取响应
                response = (HttpWebResponse)request.GetResponse();
                responseStream = response.GetResponseStream();

                // 将响应流读取到内存流
                memoryStream = new MemoryStream();
                responseStream.CopyTo(memoryStream);

                return memoryStream.ToArray();
            }
            catch (WebException ex)
            {
                // 错误处理...
            }
            finally
            {
                requestStream?.Dispose();
                responseStream?.Dispose();
                response?.Dispose();
                memoryStream?.Dispose();
            }
            return default(byte[]);
        }

        private static void initRequest(Dictionary<string, string> header, string url, string body, bool isPost, string tagId = null)
        {
            // Accept                
            string accept = "application/json";// "*/*";
            header.Add("Accept", accept);

            // ContentType  
            string contentType = "application/json";
            header.Add("Content-Type", contentType);

            //if (tagId != null && tagId != "deafultNo")
            //{
            //    header.Add("tagId", tagId);
            //}
            if (isPost)
            {
                // content-md5，be careful it must be lower case.
                string contentMd5 = computeContentMd5(body);
                header.Add("content-md5", contentMd5);
            }

            // x-ca-timestamp
            string timestamp = ((DateTime.Now.Ticks - TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0)).Ticks) / 1000).ToString();
            header.Add("x-ca-timestamp", timestamp);

            // x-ca-nonce
            string nonce = System.Guid.NewGuid().ToString();
            header.Add("x-ca-nonce", nonce);

            // x-ca-key
            header.Add("x-ca-key", _appkey);

            // build string to sign
            string strToSign = buildSignString(isPost ? "POST" : "GET", url, header);
         
            string signedStr = computeForHMACSHA256(strToSign, _secret);

            // x-ca-signature
            header.Add("x-ca-signature", signedStr);

            if (_isHttps)
            {

                ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(remoteCertificateValidate);
                //ServicePointManager.SecurityProtocol = (SecurityProtocolType)48 /*| (SecurityProtocolType)3072*/ /*| (SecurityProtocolType)768 *//*| (SecurityProtocolType)192*/;
                //ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
            }
        }

        /// <summary>
        /// 计算content-md5
        /// </summary>
        /// <param name="body"></param>
        /// <returns>base64后的content-md5</returns>
        private static string computeContentMd5(string body)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] result = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(body));
            return Convert.ToBase64String(result);
        }

        /// <summary>
        /// 远程证书验证
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="cert"></param>
        /// <param name="chain"></param>
        /// <param name="error"></param>
        /// <returns>验证是否通过，始终通过</returns>
        private static bool remoteCertificateValidate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error)
        {
            return true;
        }

        /// <summary>
        /// 计算HMACSHA265
        /// </summary>
        /// <param name="str">待计算字符串</param>
        /// <param name="secret">平台APPSecet</param>
        /// <returns>HMAXH265计算结果字符串</returns>
        private static string computeForHMACSHA256(string str, string secret)
        {
            if (secret.IsNullOrEmpty())
                return secret;
            var encoder = new System.Text.UTF8Encoding();
            byte[] secretBytes = encoder.GetBytes(secret);
            byte[] strBytes = encoder.GetBytes(str);
            var opertor = new HMACSHA256(secretBytes);
            byte[] hashbytes = opertor.ComputeHash(strBytes);
            return Convert.ToBase64String(hashbytes);
        }

        /// <summary>
        /// 计算签名字符串
        /// </summary>
        /// <param name="method">HTTP请求方法，如“POST”</param>
        /// <param name="url">接口Url，如/artemis/api/resource/v1/org/advance/orgList</param>
        /// <param name="header">请求头</param>
        /// <returns>签名字符串</returns>
        private static string buildSignString(string method, string url, Dictionary<string, string> header)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(method.ToUpper()).Append("\n");
            if (null != header)
            {
                if (null != header["Accept"])
                {
                    sb.Append((string)header["Accept"]);
                    sb.Append("\n");
                }

                if (header.Keys.Contains("Content-MD5") && null != header["Content-MD5"])
                {
                    sb.Append((string)header["Content-MD5"]);
                    sb.Append("\n");
                }

                if (null != header["Content-Type"])
                {
                    sb.Append((string)header["Content-Type"]);
                    sb.Append("\n");
                }

                if (header.Keys.Contains("Date") && null != header["Date"])
                {
                    sb.Append((string)header["Date"]);
                    sb.Append("\n");
                }
            }

            // build and add header to sign
            string signHeader = buildSignHeader(header);
            sb.Append(signHeader);
            sb.Append(url);
            return sb.ToString();
        }

        /// <summary>
        /// 计算签名头
        /// </summary>
        /// <param name="header">请求头</param>
        /// <returns>签名头</returns>
        private static string buildSignHeader(Dictionary<string, string> header)
        {
            Dictionary<string, string> sortedDicHeader = new Dictionary<string, string>();
            sortedDicHeader = header;
            var dic = from objDic in sortedDicHeader orderby objDic.Key ascending select objDic;

            StringBuilder sbSignHeader = new StringBuilder();
            StringBuilder sb = new StringBuilder();
            foreach (KeyValuePair<string, string> kvp in dic)
            {
                if (kvp.Key.Replace(" ", "").Contains("x-ca-"))
                {
                    sb.Append(kvp.Key + ":");
                    if (!string.IsNullOrWhiteSpace(kvp.Value))
                    {
                        sb.Append(kvp.Value);
                    }
                    sb.Append("\n");
                    if (sbSignHeader.Length > 0)
                    {
                        sbSignHeader.Append(",");
                    }
                    sbSignHeader.Append(kvp.Key);
                }
            }

            header.Add("x-ca-signature-headers", sbSignHeader.ToString());

            return sb.ToString();
        }

        /// <summary>
        /// 平台ip
        /// </summary>
        private static string _ip;

        /// <summary>
        /// 平台端口
        /// </summary>
        private static int _port = 443;

        /// <summary>
        /// 平台APPKey
        /// </summary>
        private static string _appkey;

        /// <summary>
        /// 平台APPSecret
        /// </summary>
        private static string _secret;

        /// <summary>
        /// 是否使用HTTPS协议
        /// </summary>
        private static bool _isHttps = true;
    }
}
